package com.sen.common.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ClassUtils;

/**
 * 反射工具类
 * 
 * @author sen
 */
public class ReflectUtil {
	
	/** slf4j logger 日志记录器 */
	private static Logger LOG = LoggerFactory.getLogger(ReflectUtil.class);
	
	private ReflectUtil() {
		// empty!
	}

	/**
	 * 根据类名创建一个实例
	 * 
	 * @param className
	 *            完整类名
	 * @return Object
	 * @throws LinkageError
	 * @throws ClassNotFoundException
	 * @throws BeanInstantiationException
	 */
	public static Object newInstance(String className)
			throws BeanInstantiationException, ClassNotFoundException, LinkageError {
		return BeanUtils.instantiate(ClassUtils.forName(className, Thread.currentThread().getContextClassLoader()));
	}
	
	/**
	 * 对目标对象中的set方法进行调用, 设置目标对象中的属性的具体值.
	 * 
	 * @param target
	 *            目标对象
	 * @param fieldName
	 *            属性变量名
	 * @param fieldType
	 *            属性类型
	 * @param fieldValue
	 *            具体值
	 */
	public static void setFieldValue(Object target, String fieldName, Class<?> fieldType, Object fieldValue) {
		boolean isFieldTypeRight = (fieldType != null) && (!(fieldType.isAssignableFrom(fieldValue.getClass())));
		if ((target == null) || StringUtils.isBlank(fieldName) || isFieldTypeRight) {
			return;
		}
		Class<?> clazz = target.getClass();
		try {
			String methodName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
			Method method = clazz.getDeclaredMethod(methodName, new Class[] { fieldType } );

			if (!(Modifier.isPublic(method.getModifiers()))) {
				method.setAccessible(true);
			}
			method.invoke(target, new Object[] { fieldValue } );
		} catch (Exception me) {
			try {
				Field field = clazz.getDeclaredField(fieldName);
				if (!(Modifier.isPublic(field.getModifiers()))) {
					field.setAccessible(true);
				}
				field.set(target, fieldValue);
			} catch (Exception fe) {
				LOG.error("反射失败", fe);
				throw new RuntimeException(fe);
			}
		}
	}
}
